#ifndef M_XMLREADER_H
#define M_XMLREADER_H

#include "refptr.h"

#include <vector>
#include <string>
#include <map>
#include <algorithm>

namespace Engine
{
	/*********************************************************************************************************************/
	template<class O, class Arg1, class Arg2,class Result>
	class mem_fun2_obj_t
	{
	public:
		typedef Result (O::*FUN_PTR)(Arg1,Arg2);

		mem_fun2_obj_t(O* obj,FUN_PTR func):m_obj(obj),m_func(func){}
		
		Result operator()(Arg1 arg1, Arg2 arg2)
		{
			return (m_obj->*m_func)(arg1,arg2);
		}
	private:
		O*      m_obj;
		FUN_PTR m_func;
	};
	/*********************************************************************************************************************/
	template<class O, class Arg1, class Arg2,class Result>
	mem_fun2_obj_t<O,Arg1,Arg2,Result> mem_fun2_obj(O* obj,Result (O::*func)(Arg1,Arg2))
	{
		return mem_fun2_obj_t<O,Arg1,Arg2,Result>(obj,func);
	}
	/*********************************************************************************************************************/
	void ToLower(std::string& str);
	/*********************************************************************************************************************/
	template<class T,class F>
	void TraverseElemets(T pElem, F func)
	{
		T elem = pElem;
		for(; !elem.IsNull(); elem = elem->NextSiblingElement())
		{
			std::string name = elem->Value();
			ToLower(name);		
			func(elem,name);
		}
	}	

	/*********************************************************************************************************************/
	template<class T,class F>
	void TraverseAttributes(T pAttr, F func)
	{
		T attr = pAttr;
		for(; !attr.IsNull(); attr = attr->Next())
		{
			std::string name = attr->Name();
			ToLower(name);
			func(name,attr->Value());
		}
	}
	/*********************************************************************************************************************/
	/**
	*   Interface class for xml attributes.
	*/
	class XmlAttribute
	{
	public:
		virtual ~XmlAttribute(){}
		virtual RefPtr<XmlAttribute> Next() = 0;
		virtual std::string Name() = 0;
		virtual std::string Value() = 0;
	};
	/*********************************************************************************************************************/
	/**
	*   Interface class for xml elements.
	*/
	class XmlElement
	{
	public:
		virtual ~XmlElement(){}
		virtual RefPtr<XmlElement>   NextSiblingElement() = 0;
		virtual RefPtr<XmlElement>   FirstChildElement() = 0;
		virtual RefPtr<XmlAttribute> FirstAttribute() = 0;
		virtual std::string Value() = 0;
	};
	/*********************************************************************************************************************/
	/**
	*   Interface class for xml document.
	*/
	class XmlDocument
	{
	public:
		virtual ~XmlDocument(){}
		virtual bool Load(const std::string& fname) = 0;
		virtual bool Parse(const char* buf) = 0;
		virtual RefPtr<XmlElement> FirstChildElement() = 0;
		virtual std::string ErrorDesc() = 0;
	};
	/*********************************************************************************************************************/
	template<class T>
	class ValuesReader
	{
	public:
		ValuesReader(const std::vector<std::string>& elems):m_elems(elems){}

		ValuesReader(std::string e0, std::string e1 = "", std::string e2 = "", std::string e3 = "")
		{
			if(!e0.empty())
				m_elems.push_back(e0);
			if(!e1.empty())
				m_elems.push_back(e1);
			if(!e2.empty())
				m_elems.push_back(e2);
			if(!e3.empty())
				m_elems.push_back(e3);
		}

		void Read(const std::string& name, const std::string& value)
		{
			std::vector<std::string>::iterator i = std::find(m_elems.begin(),m_elems.end(),name);
			if(i != m_elems.end())
			{
				T val;
				std::stringstream buf(value);
				buf >> val;
				m_values[name] = val;
			}
			else
				throw std::logic_error("Unknown xml element");
		}

		T& operator[](const std::string& elem)
		{
			return m_values[elem];
		}

	private:
		std::map<std::string,T> m_values;
		std::vector<std::string> m_elems;
	};
	/*********************************************************************************************************************/	
}
#endif
